package com.crm.controller;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.crm.entity.User;
import com.crm.service.UserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;


@Component
//访问服务端的url地址
@ServerEndpoint(value = "/websocket/{uid}/{userName}")
public class WebSocketServer {
	private static UserService userService;

	// 注入的时候，给类的 service 注入
	@Autowired
	public void setChatService(UserService userService) {
		WebSocketServer.userService = userService;
	}

	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private static int onlineCount = 0;// 记录在线人数
	private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>();// 存放在线的用户信息

	private Map<String, Object> map = new HashMap<String, Object>();// 存放要发送的信息
	private ObjectMapper objectMapper = new ObjectMapper();// 创建可以转化成json字符串的对象
	private Session session;// 与某个客户端的连接会话，需要通过它来给客户端发送数据
	private static Logger log = LogManager.getLogger(WebSocketServer.class);
	private String uid = "";
	private String userName;
	private User byId = null;
	private static ConcurrentHashMap<String, List<Object>> messageMap = new ConcurrentHashMap<>();// 存放离线消息

	/**
	 * 客服端成功建立起和服务器端连接的方法
	 *
	 * @param uid        用户id(用于各个用户之间的标识)
	 * @param userName 用户名称
	 * @param session   session 当用户在线的时候给他一个session记录一下
	 */
	@OnOpen
	public void onOpen(@PathParam(value = "uid") String uid, @PathParam(value = "userName") String userName,
			Session session) {
		try {
			if (Integer.parseInt(uid) < 0) {
				this.session = session; // 赋值
				// 重复登录
				if (webSocketSet.containsKey(uid.replace("-", ""))) {
					this.session.getBasicRemote().sendText("reLogin");
				} else {
					this.session.getBasicRemote().sendText("continue");
				}
			} else {
				this.session = session; // 赋值
				this.uid = uid;// 赋值
				this.userName = userName;// 赋值
				byId = userService.getById(uid);// 连接成功后，根据用户id查询用户
				webSocketSet.put(uid, this);// 把这个用户id记录在集合中
				addOnlineCount(); // 在线数加1
				log.info("=======================================用户" + userName + "加入！当前在线人数为" + getOnlineCount());
				if (messageMap.get(uid) != null) {// 代表这个人有未读取的消息
					List<Object> objects = messageMap.get(uid);
					for (Object object : objects) {
						sendtoUser((String) object, uid);
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		webSocketSet.remove(this.uid); // 从set中删除
		messageMap.remove(this.uid);
		subOnlineCount(); // 在线数减1
		log.info("============================================有一连接关闭！当前在线人数为" + getOnlineCount());
	}

	/**
	 * 收到客户端消息后调用的方法
	 *
	 * @param message 客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message) {
		// 可以自己约定字符串内容，比如内容|0 表示信息群发，内容|X 表示信息发给id为X的用户
		String sendMessage = message.split("[|]")[0];// 客户端发来的纯消息
		String sendUserId = message.split("[|]")[1];// 客户端要发送的用户id
		try {
			map.clear();
			if (sendMessage.equals("ding")) {
				map.put("bding", true);
				String messageObj = objectMapper.writeValueAsString(map);
				sendtoUser(messageObj, sendUserId);
				return;
			}
			System.out.println("111--->"+userName);
			System.out.println("22222---"+sdf.format(new Date()));
			System.out.println("33333---"+sendUserId);
			map.put("userName", userName);
			map.put("time", sdf.format(new Date()));
			map.put("message", sendMessage);
			map.put("count", onlineCount);
			map.put("uid", sendUserId);
			map.put("formUId", uid);
			String[] split = sendUserId.split(",");
			// 转成json格式的字符串
			String messageObj = objectMapper.writeValueAsString(map);
			if (sendUserId.equals("0")) {
				sendtoAll(messageObj);
			} else {
				for (String s : split) {// 发送指定的人（多个或者单个）
					if (uid.equals(s)) {
						continue;
					}
					if (webSocketSet.get(s) == null) {// 不在线
						if (messageMap.get(s) != null) {// 查看在不在离线名单中
							List<Object> objects1 = messageMap.get(s);
							objects1.add(messageObj);
						} else {
							List<Object> mList = new ArrayList<>();
							mList.add(messageObj);
							messageMap.put(s, mList);
						}
					} else {
						sendtoUser(messageObj, s);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		webSocketSet.remove(this);
		log.error("发生错误");
		error.printStackTrace();
	}

	/**
	 * @param message 发送自己的信息
	 * @throws IOException
	 */
	private void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
	}

	/**
	 * 发送信息给指定ID用户，如果用户不在线则返回不在线信息给自己
	 *
	 * @param message    发送的信息
	 * @param sendUserId 指定的id
	 * @throws IOException
	 */
	private void sendtoUser(String message, String sendUserId) throws IOException {
		try {
			if (webSocketSet.get(sendUserId) != null) {// 如果这个人在线
				if (!uid.equals(sendUserId)) {// 并且发送的人不是自己
					webSocketSet.get(sendUserId).sendMessage(message);// 发送给他消息
				} else {
					webSocketSet.get(uid).sendMessage(message);// 否则发送给我
				}
			} else {
				// 如果用户不在线则返回不在线信息给自己
				sendtoUser("当前用户不在线", uid);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 发送信息给所有人
	 *
	 * @param message
	 * @throws IOException
	 */
	private void sendtoAll(String message) throws IOException {
		for (String key : webSocketSet.keySet()) {
			try {
				// 得到这个键的值（WebSocketServer对象）
				webSocketSet.get(key).sendMessage(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private static synchronized int getOnlineCount() {
		return onlineCount;
	}

	private static synchronized void addOnlineCount() {
		WebSocketServer.onlineCount++;
	}

	private static synchronized void subOnlineCount() {
		WebSocketServer.onlineCount--;
	}

	public static ConcurrentHashMap<String, WebSocketServer> getWebSocketSet() {
		return webSocketSet;
	}

	public static void setWebSocketSet(ConcurrentHashMap<String, WebSocketServer> webSocketSet) {
		WebSocketServer.webSocketSet = webSocketSet;
	}
}
